import logging
import time
from abc import ABC, abstractmethod
from typing import List, Optional

import pydantic
import sqlalchemy as sa
from fastapi_pagination.bases import AbstractPage
from fastapi_pagination.ext.databases import paginate
from fastapi import Depends, Request
from like.base_service import BaseService
from like.schema_base import PageInationResult
from like.utils.db_operate import generate_query_conditions

from {{{ package_name }}}.utils.urls import UrlUtil
from {{{ package_name }}}.utils.array import ArrayUtil
from {{{ package_name }}}.models.{{{entity_snake_name}}} import {{{ entity_snake_name }}}
from {{{ package_name }}}.admin.schemas.{{{ entity_snake_name }}} import (
    {{{ entity_name }}}ListIn, {{{ entity_name }}}AddIn, {{{ entity_name }}}EditIn, {{{ entity_name }}}Out
    {% if table.is_basic_data %}, {{{ entity_name }}}OutAll{% endif %})

logger = logging.getLogger(__name__)


class I{{{ entity_name }}}Service(ABC):
    """{{{ function_name }}}抽象类"""

    @abstractmethod
    async def list(self, list_in: {{{ entity_name }}}ListIn) -> {% if table.gen_tpl == 'tree' %}List{% else %}PageInationResult{% endif %}[{{{ entity_name }}}Out]:
        pass

    @abstractmethod
    async def detail(self, id_: int) -> {{{ entity_name }}}Out:
        pass

    @abstractmethod
    async def add(self, add_in: {{{ entity_name }}}AddIn):
        pass

    @abstractmethod
    async def edit(self, edit_in: {{{ entity_name }}}EditIn):
        pass

    @abstractmethod
    async def delete(self, id_: int):
        pass

    {% if table.is_basic_data %}
    @abstractmethod
    async def all(self, all_in: {{{ entity_name }}}ListIn) -> List[{{{ entity_name }}}OutAll]:
        pass

    {% endif %}

class {{{ entity_name }}}Service(I{{{ entity_name }}}Service, BaseService):
    """{{{ function_name }}}实现类"""
    tableModel = {{{ entity_snake_name }}}

    def __init__(self, request: Request):
        super().__init__(request)

    @classmethod
    async def instance(cls, request: Request):
        """实例化"""
        return cls(request)

    async def list(self, list_in: {{{ entity_name }}}ListIn) -> {% if table.gen_tpl == 'tree' %}List[dict]{% else %}PageInationResult[{{{ entity_name }}}Out]{% endif %}:
        """{{{ function_name }}}列表"""
        columns = [
            self.tableModel,
            {% if table.sub_table_name and table.sub_table_fk and sub_table_fields %}sa.text(','.join(({% for field in sub_table_fields %}'{{{ field }}}', {% endfor %}))){% endif %}
            ]
        {%- if table.sub_table_name and table.sub_table_fk and sub_table_fields %}
        sub_table = sa.text('SELECT * FROM la_{{{ table.sub_table_name }}}') \
            .columns({% for sub_column in sub_columns %}{{{ sub_column.column_name }}}=sa.{{{ model_type_map.get(sub_column.java_type) or sub_column.java_type }}}, {% endfor %})
        {%- endif %}
        where = generate_query_conditions(list_in, self.tableModel)
        {%- if 'is_delete' in all_fields %}
        where.append(self.tableModel.c.is_delete == 0)
        {%- endif %}
        query = sa.select(*columns).where(*where) \
            .select_from(
            self.tableModel
            {%- if table.sub_table_name and table.sub_table_fk and sub_table_fields %}
                .outerjoin(sub_table, self.tableModel.c.{{{ table.sub_table_fk }}} == sub_table.c.{{{ sub_pri_field }}})
            {%- endif %}
        {%- if 'sort' in all_fields %}
        ).order_by(self.tableModel.c.sort.desc(), self.tableModel.c.id)
        {%- else %}
        ).order_by(self.tableModel.c.id)
        {%- endif %}
        {%- if table.gen_tpl == 'tree' %}
        data = await self.conn.fetch_all(query)
        res = ArrayUtil.list_to_tree(
            [i.dict(exclude_none=True) for i in pydantic.parse_obj_as(List[{{{ entity_name }}}Out], data)],
            '{{{ table.tree_primary }}}', '{{{ table.tree_parent }}}', 'children')
        {%- else %}
        res = await paginate(self.conn, query)
        {%- endif %}
        return res

    async def detail(self, id_: int) -> {{{ entity_name }}}Out:
        """{{{ function_name }}}详情"""
        model = await self.conn.fetch_one(
            self.tableModel.select().where(
                self.tableModel.c.{{{ primary_key }}} == id_{% if 'is_delete' in all_fields %}, self.tableModel.c.is_delete == 0{%- endif %})
            .limit(1))
        assert model, '数据不存在!'
        res = {{{ entity_name }}}Out.from_orm(model)
        {%- for column in columns %}
        {%- if column.is_edit and column.java_field in ['image', 'avatar', 'logo', 'img'] %}
        res.{{{ column.java_field }}} = await UrlUtil.to_relative_url(res.{{{ column.java_field }}})
        {%- endif %}
        {%- endfor %}
        return res

    async def add(self, add_in: {{{ entity_name }}}AddIn):
        """{{{ function_name }}}新增"""
        values = add_in.dict(exclude_none=True)
        await self.conn.execute(self.tableModel.insert().values(values))

    async def edit(self, edit_in: {{{ entity_name }}}EditIn):
        """{{{ function_name }}}编辑"""
        assert await self.conn.fetch_one(
            self.tableModel.select().where(
                self.tableModel.c.{{{ primary_key }}} == edit_in.id{% if 'is_delete' in all_fields %}, self.tableModel.c.is_delete == 0{%- endif %})
            .limit(1)), '数据不存在!'

        values = edit_in.dict(exclude_none=True)
        await self.conn.execute(
            self.tableModel.update().where(self.tableModel.c.{{{ primary_key }}} == edit_in.id).values(values))

    async def delete(self, id_: int):
        """{{{ function_name }}}删除"""
        assert await self.conn.fetch_one(
            self.tableModel.select().where(
                self.tableModel.c.{{{ primary_key }}} == id_{% if 'is_delete' in all_fields %}, self.tableModel.c.is_delete == 0{%- endif %})
            .limit(1)), '数据不存在!'
        {%- if 'is_delete' in all_fields %}
        await self.conn.execute(
            self.tableModel.update().where(self.tableModel.c.{{{ primary_key }}} == id_).values({
                'is_delete': 1,
                'delete_time': int(time.time()),
            }))
        {%- else %}
        await self.conn.execute(self.tableModel.delete().where(self.tableModel.c.{{{ primary_key }}} == id_))
        {%- endif %}

    {% if table.is_basic_data %}
    async def all(self, all_in: {{{ entity_name }}}ListIn) -> List[{{{ entity_name }}}OutAll]:
        """{{{ function_name }}}所有"""
        where = generate_query_conditions(all_in, self.tableModel)
        {%- if 'is_delete' in all_fields %}
        where.append(self.tableModel.c.is_delete == 0)
        {%- endif %}
        query = sa.select(self.tableModel).where(*where) \
            .select_from(
            self.tableModel
            {%- if table.sub_table_name and table.sub_table_fk and sub_table_fields %}
                .outerjoin(sub_table, self.tableModel.c.{{{ table.sub_table_fk }}} == sub_table.c.{{{ sub_pri_field }}})
            {%- endif %}
        {%- if 'sort' in all_fields %}
        ).order_by(self.tableModel.c.sort.desc(), self.tableModel.c.id)
        {%- else %}
        ).order_by(self.tableModel.c.id)
        {%- endif %}
        all_row = await self.conn.fetch_all(query)
        return pydantic.parse_obj_as(List[{{{ entity_name }}}OutAll], all_row)
    {% endif %}